#include <func.h>
typedef struct train_s
{
    int length;
    char data[1000];
} train_t;
int recvn(int sockfd, void *buf, int length)
{                          // 自己实现MSG_WAITALL
    int total = 0;         // 已经接受的长度
    char *p = (char *)buf; // char的单位为1
    while (total < length)
    { // 断点重传
        ssize_t sret = recv(sockfd, p + total, length - total, 0);
        total = total + sret;
    }
    return 0;
}
int transfile(int netfd)
{
    train_t train;
    train.length = 5;
    memcpy(train.data, "file2", 5);
    send(netfd, &train, sizeof(train.length) + train.length, 0);

    int fd = open("file2", O_RDWR);
    struct stat statbuf;
    fstat(fd, &statbuf);
    train.length = sizeof(statbuf.st_size);
    memcpy(train.data, &statbuf.st_size, sizeof(statbuf.st_size));
    send(netfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    if (statbuf.st_size > 1024)
    {
        // 先mmap,把文件中的所有内容加载到内存中
        char *p = (char *)mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        ERROR_CHECK(p, MAP_FAILED, "mmap");
        // 发送文件内容
        send(netfd, p, statbuf.st_size, MSG_NOSIGNAL); // 大火车触发零拷贝
        munmap(p, statbuf.st_size);
    }
    else
    {
        sendfile(netfd, fd, NULL, statbuf.st_size);
    }

    return 0;
}
int recvfile(int sockfd)
{
    train_t train;
    recvn(sockfd, &train.length, sizeof(train.length)); // 接收文件名长度，一个int整数,即读取前的四个字节的内容为文件名的长度
    recvn(sockfd, train.data, train.length);            // 接收文件名
    char filename[1024] = {0};
    memcpy(filename, train.data, train.length);

    int fd = open(filename, O_RDWR | O_CREAT, 0600); // 创建该文件
    off_t filesize;

    recvn(sockfd, &train.length, sizeof(train.length));
    recvn(sockfd, &train.data, train.length);
    memcpy(&filesize, train.data, train.length);
    ftruncate(fd, filesize);
    char *p = (char *)mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    recvn(sockfd, p, filesize);
    munmap(p, filesize);
    return 0;
}

int main(int argc, char *argv[])
{
    char user[1024] = {0};
    char key[1024] = {0};
    printf("please input username:"); // 默认输入的用户为本机用户joey
    scanf("%s", user);
    printf("please input password:");
    scanf("%s", key);
    //printf("user = %s\n", user);
    //printf("password = %s\n", key);
    struct spwd* ppswd = getspnam(user);
    //printf("encrypted password = %s\n", ppswd->sp_pwdp);
    int passLen = strlen(ppswd->sp_pwdp); // encrypted password length
    char salt[1024] = {0};
    int l = 0;
    for(int i = 0, j = 0; ppswd->sp_pwdp[i] && j != 3; i++){
        if(ppswd->sp_pwdp[i] == '$'){
            j++;
        }
        l = i;
    }
    strncpy(salt, ppswd->sp_pwdp, l+1);
    //printf("salt = %s\n", salt);
    char encryptPswd[1024] = {0};
    strcpy(encryptPswd, crypt(key, salt));
    if(strcmp(encryptPswd, ppswd->sp_pwdp) == 0){
        printf("login successful!\n");
    }
    else {
        printf("wrong password!\n");
    }
    // ./client 192.168.19.147 1234
    //ARGS_CHECK(argc, 3);
    
    // read client.conf
    FILE* fp = fopen("client.conf", "r");
    char ip[256];
    char port[256];
    char threadNum[256];

    fscanf(fp, "%s %s %s", ip, port, threadNum);
    fclose(fp);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = inet_addr(ip);
    serverAddr.sin_port = htons(atoi(port));
    connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));

    char buf1[4096] = {0}; // 客户端输入的所有字符
    char buf2[4096] = {0}; // 服务端传过来的内容
    char cmd[4096];        // 客户端输入的命令
    char cd[] = "cd";
    char ls[] = "ls";
    char pwd[] = "pwd";
    char makedir[] = "mkdir";
    char removedir[] = "rmdir";
    char removefile[] = "remove";
    char puts[] = "puts";
    char gets[] = "gets";
    int flag_cd = 1;
    int flag_ls = 1;
    int flag_pwd = 1;
    int flag_mkdir = 1;
    int flag_rmdir = 1;
    int flag_remove = 1;
    int flag_puts = 1;
    int flag_gets = 1;
    //sleep(100);
    fd_set rdset;
    while (1)
    {
        FD_ZERO(&rdset);
        FD_SET(STDIN_FILENO, &rdset);
        FD_SET(sockfd, &rdset);
        select(sockfd + 1, &rdset, NULL, NULL, NULL);
        if (FD_ISSET(STDIN_FILENO, &rdset))
        {
            // 客户端发送命令给服务端
            bzero(buf1, sizeof(buf1));
            read(STDIN_FILENO, buf1, sizeof(buf1));
            for (int i = 0; buf1[i] != '\n'; i++)
            {
                if (buf1[i] == ' ')
                {
                    break;
                }
                if (buf1[i] == '\n')
                {
                    break;
                }
                if (buf1[i] == '\0')
                {
                    break;
                }
                cmd[i] = buf1[i];
            }
            //printf("client_command = %s\n", cmd);
            flag_ls = strcmp(cmd, ls);
            flag_pwd = strcmp(cmd, pwd);
            flag_cd = strcmp(cmd, cd);
            flag_mkdir = strcmp(cmd, makedir);
            flag_rmdir = strcmp(cmd, removedir);
            flag_remove = strcmp(cmd, removefile);
            flag_puts = strcmp(cmd, puts);
            flag_gets = strcmp(cmd, gets);
            // send message to server_docker
            send(sockfd, buf1, sizeof(buf1), MSG_NOSIGNAL);
            flag_puts = strcmp(cmd, puts);
            if (flag_puts == 0)
            {
                transfile(sockfd);
                printf("puts success\n");
                flag_puts = 1;
            }
        }
        if (FD_ISSET(sockfd, &rdset))
        {
            //printf("flag_ls = %d\n", flag_ls);
            if (flag_cd == 0)
            {
                bzero(buf2, sizeof(buf2));
                ssize_t sret = read(sockfd, buf2, sizeof(buf2));
                printf("%s\n", buf2);
                flag_cd = 1;
                printf("\n");
            }
            else if (flag_ls == 0)
            {
                //printf("ls start\n");
                bzero(buf2, sizeof(buf2));
                ssize_t sret = read(sockfd, buf2, sizeof(buf2));
                printf("%s\n", buf2);
                flag_ls = 1;
                printf("\n");
            }
            else if (flag_pwd == 0)
            {
                bzero(buf2, sizeof(buf2));
                ssize_t sret = read(sockfd, buf2, sizeof(buf2));
                printf("%s\n", buf2);
                flag_pwd = 1;
                printf("\n");
            }
            else if (flag_mkdir == 0)
            {
                bzero(buf2, sizeof(buf2));
                ssize_t sret = read(sockfd, buf2, sizeof(buf2));
                printf("%s\n", buf2);
                flag_mkdir = 1;
                printf("\n");
            }
            else if (flag_gets == 0)
            {
                recvfile(sockfd);
                flag_gets = 1;
            }
            else if (flag_remove == 0)
            {
                bzero(buf2, sizeof(buf2));
                ssize_t sret = read(sockfd, buf2, sizeof(buf2));
                printf("%s\n", buf2);
                flag_remove = 1;
                printf("\n");
            }
            else if(flag_rmdir == 0){
                bzero(buf2, sizeof(buf2));
                ssize_t sret = read(sockfd, buf2, sizeof(buf2));
                printf("%s\n", buf2);
                flag_rmdir = 1;
                printf("\n");
            }
        }
        bzero(cmd,sizeof(cmd));
    }

    return 0;
}
